#ifndef _ICELL_H
#define _ICELL_H

#include "point.h"

#include <iostream>
#include <vector>

// ===============================================================
//  Déclaration de la classe virtuelle i-cellule : VirtualICell
// ===============================================================

class VirtualICell
{
	public:
		virtual void Remove() = 0;
		virtual int GetDim() const = 0;
		virtual const std::vector<VirtualICell*>* GetBorderCells() = 0;
		virtual void Display() = 0;
};


// ===============================================================
//  Déclaration de la classe i-cellule : ICell
//  Hérite de VirtualICell.
// ===============================================================

static int nbCellCreate = 0;
static int nbCellDelete = 0;

template<int t_iDimCell, int t_iDimPoint, typename t_Type>
class ICell : public VirtualICell
{
	public:
		ICell();
		~ICell() {}
		
		void Remove();
		int GetDim() const { return t_iDimCell; }
		const std::vector<VirtualICell*>* GetBorderCells() { return &m_picBorderCells; }
		void Display();

	private:
		std::vector<VirtualICell*> m_picBorderCells;
};



// ===============================================================
//  Spécialisation de i-cellule pour les cellules de dimmension 0.
//  Hérite de VirtualICell.
// ===============================================================

template<int t_iDimPoint, typename t_Type>
class ICell<0, t_iDimPoint, t_Type> : public VirtualICell
{
	public:
		ICell() : m_pPoint(*(new Point<t_iDimPoint, t_Type>())) { nbCellCreate++; std::cout << "0 nbCell Create : " << nbCellCreate << std::endl; }
		~ICell() {}
		
		void Remove();
		
		int GetDim() const { return 0; }
		const std::vector<VirtualICell* >* GetBorderCells() { return NULL; }
		const Point<t_iDimPoint, t_Type>& GetPoint() const { return m_pPoint; }
		void Display();
		
	private:
		Point<t_iDimPoint, t_Type>& m_pPoint;
};



// ===============================================================
//  Implémentation des fonctions membres.
// ===============================================================

template<int t_iDimCell, int t_iDimPoint, typename t_Type>
ICell<t_iDimCell, t_iDimPoint, t_Type>::ICell()
{
	nbCellCreate++;
	std::cout << "nbCell Create : " << nbCellCreate << std::endl;
	
	for(int i = 0; i < 2 * t_iDimCell; i++)
		m_picBorderCells.push_back(new ICell<t_iDimCell - 1, t_iDimPoint, t_Type>());
}

// ---------------------------------------------------------------
template<int t_iDimCell, int t_iDimPoint, typename t_Type>
void ICell<t_iDimCell, t_iDimPoint, t_Type>::Remove()
{
	for (int i = 0; i < m_picBorderCells.size(); i++)
	{
		m_picBorderCells[i]->Remove();
		delete this;
		
		nbCellDelete++;
		std::cout << "nbCell Delete : " << nbCellDelete << std::endl;
	}
}

// ---------------------------------------------------------------
template<int t_iDimPoint, typename t_Type>
void ICell<0, t_iDimPoint, t_Type>::Remove()
{
	delete &m_pPoint;
	
	nbCellDelete++;
	std::cout << "nbCell Delete : " << nbCellDelete << std::endl;
}


// ---------------------------------------------------------------
template<int t_iDimCell, int t_iDimPoint, typename t_Type>
void ICell<t_iDimCell, t_iDimPoint, t_Type>::Display()
{
	std::cout << "Dimension " << t_iDimCell << std::endl;
	for (int i = 0; i < m_picBorderCells.size(); i++)
		m_picBorderCells[i]->Display();
}


// ===============================================================
//  Implémentation des fonctions membres.
//  Spécifique à la dimension 0.
// ===============================================================

template<int t_iDimPoint, typename t_Type>
void ICell<0, t_iDimPoint, t_Type>::Display()
{
	std::cout << "Dimension 0" << std::endl;
	for (int i = 0; i < t_iDimPoint; i++)
		std::cout << "point " << i << " : " << m_pPoint.GetCoordonate(i) << std::endl;
}


#endif // _ICELL_H
